package cc.shacocloud.mirage.maven.plugin;

import org.jetbrains.annotations.NotNull;

import java.util.Objects;
import java.util.function.Supplier;

/**
 * 日志顶层接口
 *
 * @author 思追(shaco)
 */
public interface Logging {
    
    /**
     * 打印 debug 日志
     */
    void logDebug(@NotNull Supplier<String> supplier);
    
    /**
     * 打印 debug 日志
     */
    void logDebug(@NotNull Supplier<String> supplier, Object... args);
    
    /**
     * 打印 info 日志
     */
    void logInfo(@NotNull Supplier<String> supplier);
    
    /**
     * 打印 info 日志
     */
    void logInfo(@NotNull Supplier<String> supplier, Object... args);
    
    /**
     * 打印 warn 日志
     */
    void logWarn(@NotNull Supplier<String> supplier);
    
    /**
     * 打印 warn 日志
     */
    void logWarn(@NotNull Supplier<String> supplier, Object... args);
    
    /**
     * 打印 error 日志
     */
    void logError(@NotNull Supplier<String> supplier);
    
    /**
     * 打印 error 日志
     */
    void logError(@NotNull Supplier<String> supplier, Object... args);
    
    /**
     * 日志记录
     *
     * @param message        消息/模板  占位符 {}
     * @param args           参数，异常通常放在最后一个
     * @param loggingHandler 日志处理器
     */
    default void logging(@NotNull String message, @NotNull Object[] args, @NotNull LoggingHandler loggingHandler) {
        Object[] paramArgs = args;
        Throwable cause = null;
        
        if (Objects.nonNull(paramArgs) && paramArgs.length > 0) {
            Object arg = args[args.length - 1];
            if (arg instanceof Throwable) {
                paramArgs = new Object[args.length - 1];
                System.arraycopy(args, 0, paramArgs, 0, args.length - 1);
                cause = (Throwable) arg;
            }
        }
        
        message = Utils.format(message, paramArgs);
        if (Objects.isNull(cause)) {
            loggingHandler.log(message);
        } else {
            loggingHandler.log(message, cause);
        }
    }
    
    /**
     * @see Logging#logging(String, Object[], LoggingHandler)
     */
    interface LoggingHandler {
        
        void log(String message);
        
        void log(String message, Throwable cause);
    }
    
    /**
     * 不输出日志记录
     */
    class NotOutputLogging implements Logging {
        
        @Override
        public void logDebug(@NotNull Supplier<String> supplier) {
        
        }
        
        @Override
        public void logDebug(@NotNull Supplier<String> supplier, Object... args) {
        
        }
        
        @Override
        public void logInfo(@NotNull Supplier<String> supplier) {
        
        }
        
        @Override
        public void logInfo(@NotNull Supplier<String> supplier, Object... args) {
        
        }
        
        @Override
        public void logWarn(@NotNull Supplier<String> supplier) {
        
        }
        
        @Override
        public void logWarn(@NotNull Supplier<String> supplier, Object... args) {
        
        }
        
        @Override
        public void logError(@NotNull Supplier<String> supplier) {
        
        }
        
        @Override
        public void logError(@NotNull Supplier<String> supplier, Object... args) {
        
        }
    }
    
    /**
     * 系统输出日志
     */
    class SystemOutLogging implements Logging {
        
        @Override
        public void logDebug(@NotNull Supplier<String> supplier) {
            printLogging("debug", supplier.get());
        }
        
        @Override
        public void logDebug(@NotNull Supplier<String> supplier, Object... args) {
            printLogging("debug", supplier.get(), args);
        }
        
        @Override
        public void logInfo(@NotNull Supplier<String> supplier) {
            printLogging("info", supplier.get());
        }
        
        @Override
        public void logInfo(@NotNull Supplier<String> supplier, Object... args) {
            printLogging("info", supplier.get(), args);
        }
        
        @Override
        public void logWarn(@NotNull Supplier<String> supplier) {
            printLogging("warn", supplier.get());
        }
        
        @Override
        public void logWarn(@NotNull Supplier<String> supplier, Object... args) {
            printLogging("warn", supplier.get(), args);
        }
        
        @Override
        public void logError(@NotNull Supplier<String> supplier) {
            printLogging("error", supplier.get());
        }
        
        @Override
        public void logError(@NotNull Supplier<String> supplier, Object... args) {
            printLogging("error", supplier.get(), args);
        }
        
        /**
         * 打印日志
         */
        private void printLogging(String prefix, String content, Object... args) {
            logging(content, args, new LoggingHandler() {
                
                @Override
                public void log(String message) {
                    System.out.println("[" + prefix + "] " + content);
                }
                
                @Override
                public void log(String message, Throwable cause) {
                    System.out.println("[" + prefix + "] " + content);
                    cause.printStackTrace(System.out);
                }
            });
            
        }
    }
    
}
